package org.dfzt.common.util.encryption;

import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.digest.SM3;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.ss.formula.functions.T;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECPoint;
import org.dfzt.common.util.XssFilterUtil;

import java.math.BigInteger;
import java.util.HashSet;
import java.util.Set;

public class SMUtils {
	//sm2加密所需
	public final static String SM2PrivKey = "9f584078e37cf2bcf9a7a0f453d39726cc44d13471c7b54aee2c862519d7115a";
	public final static String SM2PubKey = "040f50489442de9bf1dfa28b0825d1f14cda014b7462d9d4c774a2d034083200e533dc28ab9b8f0f23573238071a2809e0494711189c7be6b01ff7ac1129d6dadb";
	private static final int c1XYL = 64;
	private static final int c3L = 64;
	private static final Log log = LogFactory.getLog(SMUtils.class);

	/**
	 * SM2加密方式
	 * */
	public static String sm2Encrypt(String inString) {
		byte[] publicKey = Util.hexToByte(SM2PubKey);
		byte[] data = inString.getBytes();
		StringBuilder sb = new StringBuilder(490);
		byte[] source = new byte[data.length];
		System.arraycopy(data, 0, source, 0, data.length);

		Cipher cipher = new Cipher();
		SM2 sm2 = SM2.Instance();
		ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

		ECPoint c1 = cipher.Init_enc(sm2, userKey);
		cipher.Encrypt(source);
		byte[] c3 = new byte[32];
		cipher.Dofinal(c3);
		String x = c1.getX().toBigInteger().toString(16);
		String y = c1.getY().toBigInteger().toString(16);
		StringBuilder sbX = new StringBuilder(x);
		StringBuilder sbY = new StringBuilder(y);
		while (x.length() < 64) {
			sbX.append("0" + sbX.toString());
		}
		while (y.length() < 64) {
			sbY.append("0" + sbY.toString());
		}
		sb.append(sbX.toString());
		sb.append(sbY.toString());
		sb.append(Util.byteToHex(source));
		sb.append(Util.byteToHex(c3));
		return sb.toString();
	}
	/**
	 * SM2解密方式
	 * */
	public static String sm2Decrypt(String inString) {
		try {
			byte[] privateKey = Util.hexToByte(SM2PrivKey);
			byte[] encryptedData = Util.hexToByte(inString);
			String data = Util.byteToHex(encryptedData);
			byte[] c1Bytesx = Util.hexToByte(data.substring(0,c1XYL));
			byte[] c1Bytesy = Util.hexToByte(data.substring(c1XYL,c1XYL<<1));
			byte[] c2 = Util.hexToByte(data.substring(c1XYL<<1,data.length()-c1XYL));
			byte[] c3 = Util.hexToByte(data.substring(data.length()-c3L));
			SM2 sm2 = SM2.Instance();
			BigInteger userD = new BigInteger(1, privateKey);
			ECPoint c1 = new ECPoint.Fp(new ECCurve.Fp(sm2.ecc_p, sm2.ecc_a, sm2.ecc_b),
					new ECFieldElement.Fp(sm2.ecc_p, Util.byteConvertInteger(c1Bytesx)),
					new ECFieldElement.Fp(sm2.ecc_p, Util.byteConvertInteger(c1Bytesy)));
			Cipher cipher = new Cipher();
			cipher.Init_dec(userD, c1);
			cipher.Decrypt(c2);
			cipher.Dofinal(c3);
			String s = new String(c2, "UTF-8");
			if("null".equalsIgnoreCase(s)||"undefined".equalsIgnoreCase(s)){
				return null;
			}
			return s;
		} catch (Exception e) {
			return inString;
		}
	}
	/**
	 * SM3加密方式
	 * */
	public static String sm3Encrypt(String inString) {
		SM3 sm3 = SmUtil.sm3();
		return sm3.digestHex(inString);
	}

	/**
	 * SM3完整性校验 验证sm2密文
	 * */
	public static boolean verifyIntegritySM2(String str){
		boolean flag=false;
		try {
			str= sm2Decrypt(str);
			flag=verifyIntegrityDecrypt(str);
		} catch (Exception e) {
			log.info("---验证数据不符合规范---");
		}
		return flag;
	}
	/**
	 * SM3完整性校验 验证明文
	 * */
	public static boolean verifyIntegrityDecrypt(String decryptStr){
		boolean flag=false;
		try {
			String preSM3 = decryptStr.substring(0, 64);
			String suf=decryptStr.substring(64);
			String sufSM3 = sm3Encrypt(suf);
			if(preSM3.equalsIgnoreCase(sufSM3)){
				flag=true;
			}
		} catch (Exception e) {
			log.info("---验证数据不符合规范---");
			flag=false;
		}
		return flag;
	}
	/**
	 * 比较两个密码一致性和数据完整性
	 * */
	public static boolean compareTwoPWD(String pwd1,String pwd2){
		boolean flag=false;
		boolean b1 = verifyIntegritySM2(pwd1);
		boolean b2 = verifyIntegrityDecrypt(pwd1);
		boolean bo1 = verifyIntegritySM2(pwd2);
		boolean bo2 = verifyIntegrityDecrypt(pwd2);
		if(b1&&bo1){
			flag= sm2Decrypt(pwd1).equals(sm2Decrypt(pwd2));
		} else if(b1&&bo2){
			flag= sm2Decrypt(pwd1).equals(pwd2);
		} else if(b2&&bo1){
			flag= pwd1.equals(sm2Decrypt(pwd2));
		}else if(b2&&bo2){
			flag= pwd1.equals(pwd2);
		}
		return flag;
	}

	/**
	 * @description: 验证密码是否包含用户名，是否和用户名相同
	 * @param pwd 1
     * @param userName 2
	 * @return boolean
	 * @author cuiyf
	 * @date 2020/6/23 16:41
	 */
	public static boolean checkPwdContainsUsername(String pwd, String userName){
	    boolean flag = false;
        boolean b = verifyIntegritySM2(pwd);
        if (b){
            String password = sm2Decrypt(pwd);
            if (password.equals(userName) || password.contains(userName)){
                flag = true;
            }
        }
        return flag;
    }

	/**
	 * 对JSONObject进行解密
	 * */
	public static void decryptJSONObject(JSONObject jsonObject){
		Set<String> strings = jsonObject.keySet();
		Set<String> remove=new HashSet<>();
		for (String str:strings) {
			if(!"password".equals(str)&&!"confirmPassword".equalsIgnoreCase(str)&&!"loginUserPassword".equalsIgnoreCase(str) && !"oldpassword".equalsIgnoreCase(str)){
				jsonObject.put(str, XssFilterUtil.clean(SMUtils.sm2Decrypt(jsonObject.getString(str))));
			}
			if("null".equalsIgnoreCase(String.valueOf(jsonObject.get(str)))){
				remove.add(str);
			}
		}
		for (String str:remove){
			jsonObject.remove(str);
		}
	}
}
